![]() |
|
|||||
10.3.6 Durchlaufen von mehreren Ebenen
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Eigenschaften des Wurzelelements und der Knoten | Erläuterung |
| firstChild | das erste Kindelement |
| lastChild | das letzte Kindelement |
| previousSibling | der vorhergehende Knoten |
| nextSibling | der nächste Knoten |
| parentNode | der direkte Vorfahre (das Dokument selbst besitzt keinen parentNode, der parentNode des Wurzelknotens ist leer) |
Anhand einiger Beispiele werden systematisch die Eigenschaften und Methoden der Objektbibliothek XML aufgelistet.
Gegeben sei ein XML-Dokument mit folgender Gestalt:
<?xml version="1.0" encoding="ISO-8859-1"?> <!-- **** Dieses Dokument ist für die deutsche Sprache geeignet und folgt den Konventionen der Version 1.0. **** --> <!DOCTYPE Autorenliste [ <!ELEMENT Autorenliste (Autor)+> <!ELEMENT Autor (Zuname, Vorname)+> <!ELEMENT Zuname (#PCDATA)> <!ELEMENT Vorname (#PCDATA)> <!ATTLIST Autorenliste Status CDATA #IMPLIED> ]> <Autorenliste Status="Öffentlich"> <Autor> <Zuname>Hofstadter</Zuname> <Vorname>Douglas R.</Vorname> </Autor> <Autor> <Zuname>Gardner</Zuname> <Vorname>Martin</Vorname> </Autor> <Autor> <Zuname>Ifrah</Zuname> <Vorname>Georges</Vorname> </Autor> </Autorenliste>
Abbildung 10.30 Ein einfaches Dokument
x0.Load("D:\Data\Liste.xml")
Dim x0 As New Xml.XmlDocument
Der DTD entspricht das Objekt »doctype« - eine Eigenschaft des Dokuments. Man kann beispielsweise den Inhalt mit
MessageBox.Show(x0.DocumentType.Name
auslesen. Allerdings ist dieses Objekt schreibgeschützt. Es ist also nicht möglich, per Programmierung der Dokumente eine DTD hinzuzufügen. Würde ein Namensraum verwendet werden, dann könnte man dies mit der Eigenschaft
namespaceURI
If x0.namespaceURI.ToString = "" Then MessageBox.Show("Kein Namensraum angegeben.") Else MessageBox.Show("Der Namensraum lautet: " & _ x0.namespaceURI.ToString) End If
Auch diese Eigenschaft ist, wie die DTD, schreibgeschützt. Existiert ein Namensraum, so wird das Präfix mit der Eigenschaft »prefix« herausgelöst.
Das Dokument selbst besitzt vier Knoten, wie mit der Eigenschaft
x0.childNodes.Count
leicht ermittelt werden kann. Jeder Knoten besitzt die Eigenschaft »nodeType«, über welche er näher bestimmt werden kann.
| Knotentyp | Nummer |
| None | 0 |
| Element | 1 |
| Attribute | 2 |
| Text | 3 |
| CDATA | 4 |
| EntityReference | 5 |
| Entity | 6 |
| ProcessingInstruction | 7 |
| Comment | 8 |
| Document | 9 |
| DocumentType | 10 |
| DocumentFragment | 11 |
| Notation | 12 |
| Whitespace | 13 |
| SignificantWhitespace | 14 |
| EndElement | 15 |
| EndEntity | 16 |
| XmlDeclaration | 17 |
Diese Liste finden Sie auch in der Hilfe. Diese Eigenschaft ist schreibgeschützt, was bedeutet, dass man nicht per Programmierung den Typ ändern kann, was vernünftig ist. Mit der Eigenschaft »nodeType« kann überprüft werden:
Dim x0 As New Xml.XmlDocument() Dim xmlKnoten As Xml.XmlNode Dim x1 As Xml.XmlElement Dim x2 As Xml.XmlAttribute Dim x3 As Xml.XmlText Dim x4 As Xml.XmlCDataSection Dim x5 As Xml.XmlEntityReference Dim x6 As Xml.XmlEntity Dim x7 As Xml.XmlProcessingInstruction Dim x8 As Xml.XmlComment Dim x9 As Xml.XmlDocument Dim x10 As Xml.XmlDocumentType Dim x11 As Xml.XmlDocumentFragment Dim x12 As Xml.XmlNotation Dim x17 As Xml.XmlDeclaration Dim strAusgabe As String x0.Load("D:\Data\Liste.xml") For Each xmlKnoten In x0.childNodes Select Case xmlKnoten.nodeType Case Xml.XmlNodeType.Element, _ Xml.XmlNodeType.EndElement x1 = xmlKnoten strAusgabe = x1.Name & ": " & vbCr & x1.InnerText Case Xml.XmlNodeType.Attribute x2 = xmlKnoten strAusgabe = x2.Name & ": " & vbCr & x2.InnerText Case Xml.XmlNodeType.Text x3 = xmlKnoten strAusgabe = x3.Name & ": " & vbCr & x3.InnerXml Case Xml.XmlNodeType.CDATA x4 = xmlKnoten strAusgabe = x4.Name & ": " & vbCr & x4.InnerXml Case Xml.XmlNodeType.EntityReference x5 = xmlKnoten strAusgabe = x5.Name & ": " & vbCr & x5.InnerXml Case Xml.XmlNodeType.Entity x6 = xmlKnoten strAusgabe = x6.Name & ": " & vbCr & x6.InnerXml Case Xml.XmlNodeType.ProcessingInstruction x7 = xmlKnoten strAusgabe = x7.InnerXml Case Xml.XmlNodeType.Comment x8 = xmlKnoten strAusgabe = x8.Value Case Xml.XmlNodeType.Document x9 = xmlKnoten strAusgabe = x9.Name & ": " & vbCr & x9.InnerXml Case Xml.XmlNodeType.DocumentType x10 = xmlKnoten strAusgabe = x10.Name Case Xml.XmlNodeType.DocumentFragment x11 = xmlKnoten strAusgabe = x11.Name & ": " & vbCr & x11.InnerXml Case Xml.XmlNodeType.Notation x12 = xmlKnoten strAusgabe = x12.Name & ": " & vbCr & x12.InnerXml Case Xml.XmlNodeType.XmlDeclaration x17 = xmlKnoten strAusgabe = x17.Name Case Else strAusgabe = "Unbekannter Knoten" End Select MessageBox.Show(xmlKnoten.GetType.ToString & ":" & _ vbCr & strAusgabe) Next
Abbildung 10.31 Die XML-Deklaration wird ausgelesen.
Abbildung 10.32 Der Kommentar wird ausgelesen.
Abbildung 10.33 Das Wurzelelement wird ausgelesen.
Abbildung 10.34 Die Kindelemente werden ausgelesen.
Im obigen Beispiel werden die Inhalte der vier Knoten x17, x8, x10 und x1 ausgegeben: »xml version=»1.0« encoding=»ISO-8859-1««, »**** Dieses Dokument ist für die deutsche Sprache geeignet und folgt den Konventionen der Version 1.0. ****«, »Autorenliste« und »Autorenliste: Hofstadter Douglas R. Gardner Martin Ifrah Georges«.
Statt InnerText kann vielfach auch InnerXml verwendet werden. Dann werden allerdings auch die Namen der Tags mit ausgelesen.
Wenn Sie lieber mit Zeichenketten arbeiten, dann können Sie den Typ des Knotens als String mit der Eigenschaft nodeType.ToString oder getType.To-String ermitteln. Dabei stehen die Werte zur Verfügung, die Sie in obiger Tabelle aufgelistet finden.
Übrigens ist in der XML-Spezifikation vorgesehen, dass alle Leerräume erhalten bleiben. Besonders für Kommentare ist dies wichtig, wenn sie aus mehreren Wörtern bestehen. Soll dies explizit festgelegt (oder unterbunden) werden, dann ist hierfür die Eigenschaft preserveWhiteSpace verantwortlich. Wird sie auf »True« gesetzt, dann bleiben alle Leerräume, das heißt alle Leerzeichen, Tabulatoren, Absatzwechsel und Zeilenschaltungen, erhalten.
Mit den beiden Objekten »Element« und »Node« können neue Elemente erzeugt und mit Eigenschaften versehen werden:
Dim xml As New Xml.XmlDocument() Dim xmlKD As Xml.XmlElement Dim xmlUnterKD1 As Xml.XmlElement Dim xmlUnterKD2 As Xml.XmlElement Dim xmlText As Xml.XmlText xml.Load(PFAD2) xmlKD = xml.CreateElement("Autor") xmlUnterKD1 = xml.CreateElement("Zuname") xmlUnterKD2 = xml.CreateElement("Vorname") xmlText = xml.CreateTextNode("Hawkins") xmlUnterKD1.AppendChild(xmlText) xmlText = xml.CreateTextNode("Steve") xmlUnterKD2.AppendChild(xmlText) xmlKD.AppendChild(xmlUnterKD1) xmlKD.AppendChild(xmlUnterKD2) xml.DocumentElement.AppendChild(xmlKD) xml.Save(PFAD2)
Abbildung 10.36 ... und danach
Damit der Pfad beim Speichern nicht ein zweites Mal hergeholt werden muss, kann der Speicherort mit der Eigenschaft »BaseURI« ermittelt werden.
Da nicht sicher ist, ob ein Element ein Attribut besitzt, muss überprüft werden, ob die Eigenschaft »Attributes.Count > 0« vorliegt. Falls ja, kann auf jedes Attribut zugegriffen werden. Auch hier kann wieder mit einer Objektvariablen vom Typ Xml.XmlAttribute gearbeitet werden:
Dim x0 As New Xml.XmlDocument() Dim x1 As Xml.XmlElement Dim x2 As Xml.XmlAttribute Dim strAusgabe As String x0.Load "D:\Data\Liste.xml" x1 = x0.documentElement If x1.Attributes.Count > 0 Then For Each x2 In x1.Attributes strAusgabe = strAusgabe & vbCr & _ x2. Name & ": " & x2.Value Next MessageBox(strAusgabe) End If
Abbildung 10.37 Das Attribut (alle Attribute) mit Name und Inhalt
Das Objekt DOMDocument besitzt einige »Create«-Methoden. Mit der korrekten Variablendeklaration kann an eine Objektvariable das entsprechende Objekt übergeben werden. Folgende Typen stehen hierbei zur Verfügung:
Dim x0 As New Xml.XmlDocument Dim x1 As Xml.XmlAttribute Dim x2 As Xml.XmlCDATASection Dim x3 As Xml.XmlComment Dim x4 As Xml.XmlDocumentFragment Dim x5 As Xml.XmlElement Dim x6 As Xml.XmlEntityReference Dim x7 As Xml.XmlNode Dim x8 As Xml.XmlProcessingInstruction Dim x9 As Xml.XmlText
x1 = x0.createAttribute x2 = x0.createCDATASection x3 = x0.createComment x4 = x0.createDocumentFragment x5 = x0.createElement x6 = x0.createEntityReference x7 = x0.createNode x8 = x0.createProcessingInstruction x9 = x0.createTextNode
Alle oben aufgelisteten Methoden verlangen eine Zeichenkette. Einige sind überladen, das heißt, man kann neben dem Namen auch noch einen Namespace eingeben (beispielsweise Elemente oder Attribute). Einige Methoden verlangen mehrere Attribute - wie zum Beispiel »CreateXmlDeclaration« -, wie die Version, das Encoding und die Option »standallone« eingegeben werden muss.
Das Hinzufügen von neuen Knoten umfasst immer zwei Phasen: Zuerst muss ein Knoten erzeugt werden. Dann wird der Knoten an das korrekte Elternelement angehängt. Bei den meisten create-Methoden funktioniert es auf die gleiche Weise, lediglich Attribute werden etwas anders angehängt.
Das folgende Beispiel illustriert das Vorgehen:
Sub NeueElemente() Dim x0 As New Xml.XmlDocument Dim x1 As Xml.XmlDeclaration Dim x2 As Xml.XmlComment Dim x3 As Xml.XmlElement Dim x4 As Xml.XmlAttribute Dim x5 As Xml.XmlNode Dim x6 As Xml.XmlCDATASection Dim x7 As Xml.XmlText Dim x8 As Xml.XmlDocumentFragment Dim x9 As Xml.XmlEntityReference
Ein leeres Dokument wurde erzeugt. Im ersten Schritt wird das Wurzelelement eingefügt:
x3 = x0.createElement("Wurzel") x0.appendChild(x3)
Es fehlt die Processing Instruction. Da sie vor dem Wurzelelement steht, muss sie im InsertBefore in das Dokument hineingeschrieben werden. Beachten Sie, dass der Parameter Standallone »yes« sein muss. Target liegt lediglich in der Version 1.0 vor.
x1 = x0.createXmlDeclaration _ ("1.0", "ISO-8859-1", "yes") x0.InsertBefore(x1, x0.DocumentElement)
Anschließend wird ein Kommentar erzeugt und eingefügt:
x2 = x0.createComment _ ("Dieses Beispiel dient lediglich dazu, " & _ "die create-Methoden zu zeigen.") x0.appendChild(x2)
Danach wird das Wurzelelement erzeugt und in das XML-Dokument eingefügt.
Ein Attribut wird erzeugt. Es besteht aus Attributname (»Eigenschaft«) und Wert (»feucht, lang, dunkel und braun«). Beachten Sie, dass das Attribut nicht mit der Methode appendChild hinzugefügt wird, sondern mit der Methode setNamedItem an die Sammlung »Attributes« angehängt wird:
x4 = xml.createAttribute("Eigenschaft") x4.Value = "feucht, lang, dunkel und braun" x3.Attributes.setNamedItem(x4)
Man kann übrigens ein Attribut leichter mit der Methode setAttribute anhängen. Diese Methode verlangt zwei Parameter, Name und Value:
x3.setAttribute("Eigenschaft2", "unter der Erde")
Schließlich wird ein Knoten erzeugt und an das Wurzelelement angefügt:
x5 = x0.createNode(Xml.XmlNodeType.Element, "Knoten", "") x3.appendChild(x5)
Danach wird ein CDATA-Abschnitt erzeugt, der Zeichendaten enthält, die nicht geparst werden (»>>«). Dieser Abschnitt wird an den Knoten angehängt:
x6 = x0.createCDATASection(">>") x5.appendChild(x6)
Dem Knoten wird ein Inhalt zugewiesen:
Set x7 = xml.createTextNode("und ich bin der Inhalt") x5.appendChild x7
Knoten können auch auf andere Weise erzeugt werden. Der Textinhalt kann als Eigenschaft des Knotens gesehen werden:
Set x5 = xml.createNode(Xml.XmlNode.Element, "Knoten", "") x5.InnerText = "ich bin der zweite Inhalt" x3.appendChild(x5)
Wer es lieber kurz und bündig (englisch: »quick and dirty«) haben möchte, der kann es auch wie folgt schreiben:
x3.appendChild(x0.createElement("Knoten")).AppendChild = _ (CreateTextNode("ich bin der vierte Knoten")))
Die vorhergehenden Schreibweisen sind sicherlich übersichtlicher. Vergessen Sie nicht, das gesamte Dokument zu speichern!
x0.Save("D:\Data\NeueListe.xls") End Sub
Abbildung 10.38 Das Ergebnis des XML-Dokuments, das mit VB.NET erzeugt wurde
Elemente können neu erzeugt, aber auch gelöscht werden:
x1.removeAttribute("Att1") x1.removeAttributeNode(x2) x1.removeChild(x3)
Beachten Sie, dass das Dokument danach wieder gespeichert werden muss!
Manchmal ist es nötig, dass automatisch generierte Dokumente in ihrem Inhalt oder in ihrer Struktur verändert werden. Auch dies kann mit einigen VB.NET-Befehlen, oder genauer: mit dem DOM, erledigt werden. Welche Möglichkeiten VB.NET zur Verfügung stellt und wie sie angewendet werden, wird in diesem Kapitel beschrieben. Ein ganz einfaches Beispiel könnte der XML-Export von Excel darstellen. Wenn Sie eine Excel-Mappe als XML-Datei speichern, schreibt der Filter zu viele Daten in diese Datei. Um nur die gewünschten Daten zu erhalten beziehungsweise um sie in einer bestimmten Form zu haben, könnte diese exportierte Datei transformiert werden, damit sie die passende Gestalt hat.
Mit Hilfe von appendChild können Elemente an das Wurzelelement oder an andere Elemente angefügt werden:
Dim xml As New Xml.XmlDocument Dim xmlElement As Xml.Xmllement xml.Load("D:\Data\test01.xml") Set xmlElement = xml.createElement("NeuesElement") xml.documentElement.appendChild(xmlElement).Value = _ "Hallo, ist noch wer da?" xml.Save("D:\Data\test02.xml")
Analog kann das Element mit der Methode removeChild gelöscht werden:
Dim xml As New Xml.XmlDocument Dim xmlElement As Xml.XmlElement xml.Load("D:\Data\test02.xml") xmlElement = xml.documentElement.lastChild xml.documentElement.removeChild(xmlElement) xml.Save("D:\Data\test02.xml")
Die Methode appendChild setzt das neue Element immer ans Ende der Knotenliste. Soll es an eine bestimmte Position gesetzt werden, dann kann die Methode InsertBefore verwendet werden. Beide Methoden geben einen Knoten zurück. Im folgenden Beispiel wird das neue Element am Anfang des Wurzelelements eingefügt:
Dim xml As New Xml.XmlDocument() Dim xmlElement As Xml.XmlElement xml.Load("D:\Data\test04.xml") _ xmlElement = xml.createElement("NeuesElement") xml.documentElement.InsertBefore(xmlElement, _ xml.documentElement.childNodes(0)).InnerText = _ "Hallo, ist noch wer da?" xml.Save("D:\Data\test02.xml"))
Fasst man die beiden Methoden insertBefore und removeChild zusammen, dann kann man damit leicht ein Element ersetzen:
Sub Ersetze01(xmlBossElement As Xml.XmlElement, _ xmlAltesElement As Xml.Xmllement, _ xmlNeuesElement As Xml.XmlElement) xmlBossElement.insertBefore(xmlNeuesElement, _ xmlAltesElement) xmlBossElement.removeChild(xmlAltesElement) End Sub
Diese Prozedur wird von anderer Stelle aufgerufen, beispielsweise so:
Sub XML_Bewegung01() Dim xml As New Xml.XmlDocument() Dim xmlElementErstes As Xml.XmlElement Dim xmlElementLetztes As Xml.XmlElement xml.Load("D:\Data\test02.xml") xmlElementLetztes = xml.documentElement.LastChild xmlElementErstes = xml.documentElement.FirstChild Call Ersetze01(xml.documentElement, xmlElementErstes, _ xmlElementLetztes) xml.Save("D:\Data\test02.xml") End Sub
Es geht aber mit der Methode replaceChild eleganter:
Sub Ersetze02(xmlBossElement As Xml.XmlElement, _ xmlAltesElement As Xml.XmlElement, _ xmlNeuesElement As Xml.XmlElement) xmlBossElement.replaceChild(xmlNeuesElement, _ xmlAltesElement) End Sub
Achtung: Das XML-Dokument muss bei der Methode replaceChild mindestens drei Elemente haben. Dagegen arbeitet die selbst definierte Prozedur »Ersetze01« auch mit zwei, ja sogar mit einem Element, welches nach Ablauf gelöscht ist. Während mit insertBefore ein Knoten verschoben wird, kann mit der Methode cloneNode ein Knoten kopiert werden:
Sub KopiereKnoten(xmlBossElement As Xml.XmlElement, _ xmlAltesElement As Xml.XmlElement) Dim xmlNeuesElement As Xml.XmlElement Set xmlNeuesElement = xmlAltesElement.CloneNode(True) xmlBossElement.appendChild xmlNeuesElement End Sub
Die Methode cloneNode verlangt einen Parameter deep (»True« oder »False«), der festlegt, ob die Kindknoten mitgeklont werden oder nicht.
Mit dieser Prozedur wird der letzte Knoten dupliziert und steht nun zweimal hintereinander im XML-Dokument. Soll er dagegen am Ende und am Anfang stehen, dann ist der Code um folgende Zeile zu erweitern:
xmlBossElement.insertBefore(xmlNeuesElement, _ xmlBossElement.childNodes(0))
Vielleicht mag der eine oder andere Leser nun erstaunt kommentieren, dass XML-Transformationen ja eine lustige Sache sind, aber möglicherweise keinen praktischen Sinn haben. Denn wenn ein XML-Dokument erzeugt wurde, so kann man beim Erzeugen schon auf die Daten und auf die Ebene in der Hierarchie achten, in welcher sich die Daten befinden. Kann man das immer? Was ist, wenn Sie von anderen Menschen oder Maschinen XML-Dokumente erhalten, die Ihnen in dieser Form nicht »gefallen«? Die Microsoft-Programme sind gute Beispiel für die Notwendigkeit der XML-Transformation. Wenn Sie eine Zeichnung aus Visio oder eine Tabelle aus Excel ins XML-Format exportieren, dann werden zu viele Informationen weggeschrieben, die gar nicht benötigt werden. Um dies zu verhindern oder auszugleichen, kann ein XML-Dokument in seinem Inhalt und in seiner Struktur manipuliert werden. Mit Hilfe der DOM-Transformationen können Daten restrukturiert werden.
Manchmal müssen automatisch generierte Dokumente in ihrem Inhalt oder in ihrer Struktur verändert werden. Nicht immer können XML-Dateien von Grund auf geplant und angelegt werden.
Dies kann mit einigen VB.NET-Befehlen beziehungsweise mit dem DOM, erledigt werden. Welche Möglichkeiten VB.NET hierzu zur Verfügung stellt und wie sie angewendet werden, wurde in diesem Kapitel vorgestellt. An einem Beispiel soll nun gezeigt werden, wie Daten aus einer Excel-Tabelle herausgeholt werden, nach XML geschrieben und mit einer XSL(T)-Datei verknüpft werden, damit sie im Browser die gewünschte Gestalt haben.
| << zurück |
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
Copyright © Galileo Press GmbH 2002 - 2003
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.